#ifndef MACRO_HPP
#define MACRO_HPP

#include "globals.hpp"
#include "dev/filesystem.h"
#include "dev/stepper.hpp"

#include <lvgl.h>
#include "ui/ui.h"

const char* macro_path = "/macro.txt"; // 以 / 开头的绝对路径

int macro_position = 0; // 全局变量，记录宏文件执行到的位置
bool macro_running = false; // 全局变量，标志宏是否正在执行

// 宏命令类型
enum MacroType {
    FREQ_CHANGE,  // f命令
    RPS_CHANGE,   // rps命令
    SLEEP,        // s命令
};

// 宏命令结构
struct MacroCommand {
    MacroType type;
    int motor_id; // 0:x, 1:y
    float value;  // 频率为int, rps为float, s为int
    MacroCommand* next;

    MacroCommand(MacroType t, int m, float v) : type(t), motor_id(m), value(v), next(nullptr) {}
};

// 宏命令链表管理
class MacroList {
private:
    MacroCommand* head;
    MacroCommand* current;
    
    static const int MAX_SIZE = 100;

public:
    int size;
    MacroList() : head(nullptr), current(nullptr), size(0) {}
    ~MacroList() { clear(); }

    void clear() {
        while (head) {
            MacroCommand* temp = head;
            head = head->next;
            delete temp;
        }
        current = nullptr;
        size = 0;
    }

    bool add(MacroType type, int motor_id, float value) {
        if (size >= MAX_SIZE) return false;
        MacroCommand* cmd = new MacroCommand(type, motor_id, value);
        if (!head) {
            head = cmd;
        } else {
            MacroCommand* temp = head;
            while (temp->next) temp = temp->next;
            temp->next = cmd;
        }
        size++;
        return true;
    }

    void resetCurrent() { current = head; }

    MacroCommand* getNext() {
        if (!current) return nullptr;
        MacroCommand* temp = current;
        current = current->next;
        return temp;
    }

    void showCommands() {
        MacroCommand* temp = head;
        int index = 0;
        logln("[MACRO] MACRO COMMANDS:");
        while (temp) {
            if (temp->type == FREQ_CHANGE) {
                logf("  %3d: f%d %d\n", index, temp->motor_id, (int)temp->value);
            } else if (temp->type == RPS_CHANGE) {
                logf("  %3d: rps%d %.3f\n", index, temp->motor_id, temp->value);
            } else if (temp->type == SLEEP) {
                logf("  %3d: s%d\n", index, (int)temp->value);
            }
            temp = temp->next;
            index++;
        }
        logf("[MACRO] Total %d lines of MACROS\n", size);
    }
};

MacroList macroList;

void load_macro() {

    if (!UMEKO_FS.exists(macro_path)) {
        logf("[MACRO] File \"%s\" Not exists\n", macro_path);
        return;
    }

    fs::File macroFile = UMEKO_FS.open(macro_path, "r");
    if (!macroFile) {
        logf("[MACRO] File  \"%s\" can not open\n", macro_path);
        return;
    }

    macroList.clear();
    int totalLines = 0;
    int loadedLines = 0;
    bool capacityWarning = false;
    while (macroFile.available()) {
        String line = macroFile.readStringUntil('\n');
        line.trim();
        totalLines++;

        // f0 <int> 或 f1 <int>
        if (line.startsWith("f0 ") || line.startsWith("f1 ")) {
            int motor_id = line.charAt(1) - '0';
            int speed = line.substring(3).toInt();
            if (!macroList.add(FREQ_CHANGE, motor_id, speed)) {
                if (!capacityWarning) {
                    logf("[MACRO] Warning: %d lines > 100 lines limit.\n", totalLines);
                    capacityWarning = true;
                }
            } else {
                loadedLines++;
            }
        }
        // rps0 <float> 或 rps1 <float>
        else if (line.startsWith("rps0 ") || line.startsWith("rps1 ")) {
            int motor_id = line.charAt(3) - '0';
            float rps = line.substring(5).toFloat();
            if (!macroList.add(RPS_CHANGE, motor_id, rps)) {
                if (!capacityWarning) {
                    logf("[MACRO] Warning: %d lines > 100 lines limit.\n", totalLines);
                    capacityWarning = true;
                }
            } else {
                loadedLines++;
            }
        }
        // s <int>
        else if (line.startsWith("s")) {
            int delay = line.substring(1).toInt();
            if (!macroList.add(SLEEP, 0, delay)) {
                if (!capacityWarning) {
                    logf("[MACRO] Warning: %d lines > 100 lines limit.\n", totalLines);
                    capacityWarning = true;
                }
            } else {
                loadedLines++;
            }
        }
    }
    macroFile.close();
    logf("[MACRO] MACRO loaded: totle: %d / loaded: %d \n", totalLines, loadedLines);
}

void start_macro() {
    macroList.resetCurrent();
    macro_running = true;
    macro_position = 0;
    logln("[MACRO] Macro loaded and started");
}

void stop_macro() {
    macro_running = false; // 停止宏执行模式
    macro_position = 0;    // 重置行数
    stepper_x.run_freq(0);
    stepper_y.run_freq(0);
    logln("[MACRO] Macro stopped");
}

void macro_cb(int process_id, int process_len){
    u_int8_t process_percent = process_id * 100 / process_len;
    lv_bar_set_value(ui_BarMacro, process_percent, LV_ANIM_ON);
}

void macro_looper() {
    static unsigned long lastActionTime = 0;
    static bool isDelayActive = false;
    static int delayDuration = 0;

    if (!macro_running) return;

    if (isDelayActive) {
        if (millis() - lastActionTime >= delayDuration) {
            isDelayActive = false;
        } else {
            return;
        }
    }

    MacroCommand* cmd = macroList.getNext();
    if (cmd) {
        macro_position++;
        macro_cb(macro_position, macroList.size); // 进度回调
        if (cmd->type == FREQ_CHANGE) {
            if (cmd->motor_id == 0) stepper_x.run_freq((int)cmd->value);
            else if (cmd->motor_id == 1) stepper_y.run_freq((int)cmd->value);
        } else if (cmd->type == RPS_CHANGE) {
            if (cmd->motor_id == 0) stepper_x.run_rps(cmd->value);
            else if (cmd->motor_id == 1) stepper_y.run_rps(cmd->value);
        } else if (cmd->type == SLEEP) {
            isDelayActive = true;
            delayDuration = (int)cmd->value;
            lastActionTime = millis();
        }
    } else {
        macroList.resetCurrent(); // 自动回到开头
        macro_position = 0;
        logf("[MACRO] MACRO FINISHED ONECE, RESTART\n");
    }
}

void show_macro() {
    macroList.showCommands();
}

String get_macro_content() { 
    fs::File file = UMEKO_FS.open(macro_path, "r");
    if (!file) {
        return String();
    }
    String content = file.readString();
    file.close();
    return content;
}

bool save_macro(String content){
    fs::File file = UMEKO_FS.open(macro_path, "w");
    if (!file) {
        logln("[MACRO] Failed to open file for writing");
        return false;
    }
    file.print(content);
    file.close();
    load_macro(); // 重新加载宏
    return true;
}

uint16_t get_macro_lenght(){ 
    return macroList.size;
}

#endif // MACRO_HPP